/////////////////////////////////////////////////
//	File	:	"Kori's Factory.h"
//
//	Author	:	Kori Po
//
//	Purpose	:	It makes things
//
/////////////////////////////////////////////////

#pragma once

#include <map>
using std::map;

////////////////////
/*
	Naming Covention: 
	ClassType= Class ID Type
	BaseType = BaseClassType
*/
//////////////


template <typename ClassType, typename BaseType>
class CObjectFactory
{
private:
	// Function pointer decl
	typedef BaseType* (*ObjectCreator)(void);

	// Function pointer data base
	map<ClassType, ObjectCreator> m_ObjectCreators;

	//SINGLETION
	static CObjectFactory<ClassType, BaseType> TheInstance;

	//TOE
	CObjectFactory(void){/*Do Nothing*/}
	CObjectFactory(const CObjectFactory&);
	CObjectFactory& operator=(const CObjectFactory&);

	~CObjectFactory(void) {/*Do Nothing*/};

	// Make Object
	template<typename DevClass>
	static BaseType* ConstructObject(void)
	{
		return new DevClass;
	}
	
public:
	// Get Instance
	static CObjectFactory<ClassType, BaseType>* GetInstance(void)
	{
		return &TheInstance;
	}

	// Make the map
	template<typename DevClass>
	bool RegisterClassType(ClassType ID)
	{
		// Make DB Def
		std::pair<ClassType, ObjectCreator> objTypeDef;

		objTypeDef.first	=	ID;
		objTypeDef.second	=	ConstructObject<DevClass>;

		//	Add this information into my database.
		m_ObjectCreators.insert(objTypeDef);

		//	Success.
		return true;
	}

	//Remove from map
	bool UnregisterClassType(ClassType ID)
	{
		//	Find the given key inside of the database (map).
		map<ClassType, ObjectCreator>::iterator iter = m_ObjectCreators.find(id);

		//	Error check to make sure we found it.
		if (iter == m_ObjectCreators.end())
			return false;

		//	Remove the database information.
		m_ObjectCreators.erase(iter);

		//	Success.
		return true;
	}

	//	Creates an object of the given id.
	BaseType* CreateObject(ClassType id)
	{
		map<ClassType, ObjectCreator>::iterator iter = m_ObjectCreators.find(id);

		//	Error check to make sure we found it
		if (iter == m_ObjectCreators.end())
			return NULL;

		//	Create the class type and return it.
		return (*iter).second();
	}

	void ShutdownObjectFactory(void)
	{
		//	Clear the database.
		m_ObjectCreators.clear();
	}
};

template<typename ClassType, typename BaseType>
CObjectFactory<ClassType, BaseType> 
CObjectFactory<ClassType, BaseType>::TheInstance;